package me.hetong.caigou.engine;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import javafx.application.Platform;
import lombok.Data;
import me.hetong.caigou.entity.EngineZhao;
import me.hetong.caigou.entity.Zhao;
import me.hetong.caigou.ui.stage.IndexStage;
import me.hetong.caigou.ui.view.Infer;
import me.hetong.caigou.ui.view.LineChartWebView;
import me.hetong.caigou.util.FenUtils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
 * 通用UCI引擎
 *
 * @author hetong
 */
@Data
public class UciEngine {

    private String path;
    private Process process;
    private Thread thread;
    private BufferedReader reader;
    private BufferedWriter writer;
    private EngineZhao best = null;
    private int alreadyDeep = 0;
    private String lastSearch;
    private Zhao zhao;

    private UciEngine() {
    }

    public UciEngine(String path) {
        this.path = path;
    }

    /**
     * 启动
     */
    public void startUp() {
        try {
            if (process == null && reader == null && writer == null) {
                process = Runtime.getRuntime().exec(this.path);
                reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
                readerHandle();

                cmd("uci");
//                cmd("setoption name Threads value 8");
//                cmd("setoption name Hash value 1024");
                StaticLog.info("开启引擎");

                if (zhao != null) {
                    reSearch();
                }

                IndexStage.VIEW.getMessageBean().info("启动引擎成功");
            } else {
                shutdown();
            }

        } catch (Exception e) {
            e.printStackTrace();
            IndexStage.VIEW.getMessageBean().info("引擎启动失败", e.getMessage());
        }
    }

    private void readerHandle() {
        thread = new Thread(() -> {
            while (true) {
                try {
                    if (reader != null) {
                        if (reader.ready()) {
                            String line = reader.readLine();
                            StaticLog.info(line);
                            if (StrUtil.isNotBlank(line)) {
                                extracted(line);
                            }
                        }
                    } else {
                        return;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
    }

    private void extracted(String line) {
        try {
            if (line.contains("info depth ")) {

                if (!line.contains("depth " + (alreadyDeep + 1) + " ")) {
                    return;
                }

                final EngineZhao engineZhao = new EngineZhao(line);
                if (engineZhao.getCp() == null) {
                    engineZhao.setCp(0);
                }
                alreadyDeep = engineZhao.getDepth();

                if (best == null || (engineZhao.getCp() > best.getCp()) || (engineZhao.getMoves().length() > best.getMoves().length())) {
                    best = engineZhao;
//                    Platform.runLater(() -> {
//                        Message.bottomInfo("【思考中】", "深度" + engineZhao.getDepth(), "得分" + engineZhao.getCp(), "速度" + engineZhao.getNps());
//                    });
                }
            } else if (line.contains("bestmove ")) {
                Platform.runLater(() -> {
                    if (best != null) {
                        zhao.setScore(zhao.getRed() ? -best.getCp() : best.getCp());
                        zhao.setMate(best.getMate() != null ? best.getMate() : null);

                        if (best.getMate() != null) {
                            best.setMate(zhao.getRed() ? -best.getMate() : best.getMate());
                        }

                        if (best.getMate() != null) {
                            IndexStage.VIEW.getMessageBean().info(best.getMate() + " 步杀");
                        }

                        String[] moveArray = best.getMoves().split(" ");
                        Infer.chessboardForEngine.setChessList(zhao.getFen2());
                        Infer.chessboardForEngine.setZhao(zhao);
                        for (int i = 0; i < moveArray.length; i++) {
                            Zhao tempZhao = FenUtils.moveToZhao(moveArray[i]);
                            if (i == 0) {
                                Infer.chessboardForEngine.setZhao1(tempZhao);
                            }
                            if (i == 1) {
                                Infer.chessboardForEngine.setZhao2(tempZhao);
                            }
                            if (i == 2) {
                                Infer.chessboardForEngine.setZhao3(tempZhao);
                            }
                            if (i == 3) {
                                Infer.chessboardForEngine.setZhao4(tempZhao);
                            }
                        }
                        LineChartWebView.transFromMatchData();
                        if (zhao.getIdx() != null) {
                            LineChartWebView.setHighLight(zhao.getIdx());
                        }
                    }
                });
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void cmd(String cmd) {
        if (process != null && process.isAlive()) {
            try {
                writer.write(cmd + System.getProperty("line.separator"));
                writer.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void search(Zhao zhao) {
        ThreadUtil.execute(() -> {
            alreadyDeep = 0;
            this.zhao = zhao;
            this.best = null;
            Infer.chessboardForEngine.setZhao1(null);
            Infer.chessboardForEngine.setZhao2(null);
            Infer.chessboardForEngine.setZhao3(null);
            Infer.chessboardForEngine.setZhao4(null);
            cmd("stop");
            // 如果当前拿动走的是红方棋子，计算时应该计算下一步，所以应该转为黑方走子
            cmd("position fen " + zhao.getFen2() + " " + (!zhao.getRed() ? "w" : "b"));
            cmd("go depth 20 movetime 50 mate 10");
        });
    }

    public void reSearch() {
        if (zhao != null) {
            this.search(zhao);
        }
    }

    public void shutdown() {
        try {
            if (process != null) {
                cmd("stop");
                cmd("quit");
            }

            if (thread != null) {
                thread.interrupt();
                thread = null;
            }

            if (process != null) {
                process.destroy();
                process = null;
            }

            if (reader != null) {
                reader.close();
                reader = null;
            }
            if (writer != null) {
                writer.close();
                writer = null;
            }

            Infer.chessboardForEngine.setZhao1(null);
            Infer.chessboardForEngine.setZhao2(null);
            Infer.chessboardForEngine.setZhao3(null);
            Infer.chessboardForEngine.setZhao4(null);

            IndexStage.VIEW.getMessageBean().info("关闭引擎成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}